﻿@using Microsoft.EntityFrameworkCore
@using Flagrum.Web.Features.ModManager.Services
@using Flagrum.Web.Persistence.Entities.ModManager
@using System.IO
@using Flagrum.Core.Archive
@using Flagrum.Core.Utilities.Types
@using Flagrum.Web.Features.ModManager.Data
@using Flagrum.Web.Features.ModManager.Modals
@inherits ModComponentBase

@inject NavigationManager Navigation
@inject IWpfService WpfService
@inject ILogger<ModCard> Logger
@inject ProfileService Profile

<div class="bg-grey-800 rounded shadow-lg mx-4 mt-8 cursor-pointer hover:shadow-xl hover:scale-105 transition-transform transition-shadow transform"
     style="width: 326px; height: 372px; @(IsDisabled ? "filter: grayscale(100%);" : "")"
     @onclick="@(() => Navigation.NavigateTo($"/earc/editor/{Mod.Id}"))">
    <div class="relative rounded-t" style="width: 326px; height: 170px; background-repeat: no-repeat; background-size: cover; background-position: center; background-image: url('EarcMods/@Profile.Current.Id/@(Mod.Id).png?@Timestamp')">
        <span style="position:absolute;top:5px;left:5px;font-size: 2rem;" class="material-icons cursor-pointer @(Mod.IsFavourite ? "text-accent1-200" : "")"
              @onclick="OnFavourite"
              @onclick:stopPropagation="true">
            @(Mod.IsFavourite ? "star" : "star_border")
        </span>
        <Checkbox CssStyle="position:absolute;top:5px;right:5px;"
                  IsChecked="@Mod.IsActive"
                  OnChange="ToggleMod"/>
        <div class="absolute bottom-2 left-2 border-2 border-grey-500 text-grey-300 bg-dark-600 opacity-75 inline-block rounded-full hover:bg-grey-900 hover:border-grey-300 hover:text-white cursor-pointer select-none"
             @onclick="Export"
             @onclick:stopPropagation="true"
             style="width: 38px; height: 38px; padding: 5px;">
            <span class="material-icons select-none">file_download</span>
        </div>
        @if (!string.IsNullOrWhiteSpace(Mod.Readme) && Mod.Readme.Trim() != "<p><br></p>")
        {
            <div class="absolute bottom-2 right-2 border-2 border-grey-500 text-grey-300 bg-dark-600 opacity-75 inline-block rounded-full hover:bg-grey-900 hover:border-grey-300 hover:text-white cursor-pointer select-none"
                 @onclick="ShowReadme"
                 @onclick:stopPropagation="true"
                 style="width: 38px; height: 38px; padding: 5px;">
                <span class="material-icons select-none">description</span>
            </div>
        }
    </div>
    <div class="p-4">
        <div class="row mb-2">
            <strong class="block text-grey-200 flex-grow font-display" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 280px;">@Mod.Name</strong>
            <span class="material-icons ml-3 text-accent1-200 cursor-pointer hover:text-white"
                  style="font-size: 0.95rem;"
                  @onclick="() => Parent.ShowModCardModal(Mod.Id)"
                  @onclick:stopPropagation="true">
                edit
            </span>
        </div>
        <div class="block text-grey-200 flex-grow mb-2 flex flex-row items-center">
            <span class="material-icons text-grey-200 mr-2">person</span>
            <span class="flex-grow">@Mod.Author</span>
        </div>
        <span class="text-sm">
            @(Mod.Description.Length > 171 ? Mod.Description[..170] + "..." : Mod.Description)
        </span>
    </div>
</div>

<AlertModal @ref="Alert"/>
<CascadingValue Value="this">
    <CorruptionModal @ref="CorruptionModal"/>
</CascadingValue>

@code
{
    private AlertModal Alert { get; set; }
    private long Timestamp { get; set; }
    private CorruptionModal CorruptionModal { get; set; }

    [CascadingParameter]
    public Index Parent { get; set; }

    [Parameter]
    public bool IsDisabled { get; set; }

    protected override void OnInitialized()
    {
        Timestamp = DateTime.UtcNow.Ticks;
        Prompt = Parent.Prompt;
    }

    protected override void OnAfterRender(bool firstRender)
    {
        if (Parent.CheckTimestampUpdate(Mod.Id))
        {
            Timestamp = DateTime.UtcNow.Ticks;
            StateHasChanged();
        }
    }

    private void OnFavourite()
    {
        var mod = Context.EarcMods.FirstOrDefault(e => e.Id == Mod.Id)!;
        mod.IsFavourite = !mod.IsFavourite;
        Mod.IsFavourite = !Mod.IsFavourite;
        Context.SaveChanges();
        Parent.CallStateHasChanged();
    }

    private async void ToggleMod(bool newState)
    {
        if (Context.Profile.IsGameRunning())
        {
            Mod.IsActive = !newState; // Put the checkbox back into its original state
            StateHasChanged();
            Alert.Open("Error", "FFXV is Running", "Flagrum cannot enable or disable mods while the game is running. Please save and close down FFXV, then try again.", null);
            return;
        }

        if (newState)
        {
            await Enable();
        }
        else
        {
            await Disable();
        }
    }

    private async Task Enable()
    {
        await InvokeAsync(() => Parent.SetLoading(true, "Enabling Mod"));

        await Task.Run(async () =>
        {
            var deadFiles = Context.EarcModEarcs
                .Where(e => e.EarcModId == Mod.Id)
                .SelectMany(e => e.Files
                    .Where(r => r.Type == EarcFileChangeType.Replace || r.Type == EarcFileChangeType.Add || r.Type == EarcFileChangeType.AddToTextureArray))
                .Select(r => r.ReplacementFilePath)
                .ToList()
                .Where(p => !File.Exists(p))
                .ToList();

            if (deadFiles.Any(f => !File.Exists(f)))
            {
                var message = deadFiles.Aggregate("The mod could not be built as the following files were missing:<ul class='mt-4'>",
                    (current, file) => current + $"<li>{file}</li>");
                await InvokeAsync(() => Alert.Open("Error", "Missing Files", message + "</ul>", null, 400, 300, true));
                return;
            }

            await CheckConflicts(Mod.Id, async () => await ModManagerService.EnableMod(Mod.Id));

            var success = await _taskCompletionSource.Task;
            if (!success)
            {
                Mod.IsActive = false; // Ensures the checkbox doesn't stay checked
                await InvokeAsync(StateHasChanged);
            }
        });

        await InvokeAsync(() => Parent.SetLoading(false));
    }

    private async Task Disable()
    {
        await InvokeAsync(() => Parent.SetLoading(true, "DisablingMod"));
        
        await Task.Run(() =>
        {
            try
            {
                ModManagerService.DisableMod(Mod.Id);
            }
            catch (Exception exception)
            {
                Logger.LogError(exception, "Failed to disable mod due to exception");
                InvokeAsync(() => CorruptionModal.Open(Mod.Id));
            }
        });
        
        await InvokeAsync(() => Parent.SetLoading(false));
    }

    private async Task Export()
    {
        var earcMod = Context.EarcMods
            .Include(m => m.Earcs)
            .ThenInclude(e => e.Files)
            .Include(m => m.LooseFiles)
            .Where(m => m.Id == Mod.Id)
            .AsNoTracking()
            .ToList()
            .FirstOrDefault()!;

        if (earcMod.LooseFiles.Any() || earcMod.Earcs.Any(e => e.Files
            .Any(f => f.Type is EarcFileChangeType.Add or EarcFileChangeType.AddReference or EarcFileChangeType.AddToTextureArray)))
        {
            throw new Exception("gtm detected");
        }

        if (!ModManagerService.CheckModIsCached(earcMod))
        {
            var deadFiles = earcMod.Earcs.SelectMany(e => e.Files
                .Where(r => r.Type is EarcFileChangeType.Replace or EarcFileChangeType.Add or EarcFileChangeType.AddToTextureArray
                            && !File.Exists(r.ReplacementFilePath)))
                .Select(r => r.ReplacementFilePath)
                .ToList();

            if (deadFiles.Any())
            {
                var message = deadFiles.Aggregate("The mod could not be built as the following files were missing:<ul class='mt-4'>",
                    (current, file) => current + $"<li>{file}</li>");
                Alert.Open("Error", "Missing Files", message + "</ul>", null, 400, 300, true);
                return;
            }
        }

        var defaultName = earcMod.Name.ToLower().Replace(" ", "_") + ".fmod";
        const string filter = "Flagrum Mod|*.fmod";
        await WpfService.OpenSaveFileDialogAsync(defaultName, filter, async savePath =>
        {
            await InvokeAsync(() => Parent.SetLoading(true, "ExportingModPack"));

            await Task.Run(() =>
            {
                if (ModManagerService.CheckModIsCached(earcMod))
                {
                    Fmod.FromEarcMod(earcMod, $@"{Profile.EarcImagesDirectory}\{earcMod.Id}.png", Profile.CacheDirectory).Write(savePath);
                }
                else
                {
                    using (var archiveManager = new EbonyArchiveManager())
                    {
                        ModManagerService.BuildAssetCache(earcMod, archiveManager);
                    }

                    Fmod.FromEarcMod(earcMod, $@"{Profile.EarcImagesDirectory}\{earcMod.Id}.png", Profile.CacheDirectory).Write(savePath);
                    ModManagerService.ClearCachedFilesForMod(earcMod.Id);
                }
            });

            await InvokeAsync(() => Parent.SetLoading(false));
        });
    }

    private void ShowReadme()
    {
        Parent.ShowReadme(Mod.Readme);
    }

    public void CallModListStateHasChanged() => Parent.CallStateHasChanged();
}